#pragma once
#include <pthread.h>
#include <unistd.h>
#include <iostream>
#include <vector>
#include <unordered_map>
#include <fstream>
#include <sstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string>
#include "Socket.hpp"

static const std::string sep = "\r\n";
static const std::string path = "./wwwroot";
static const std::string homepage = "index.html";
static const std::string code404 = "./wwwroot/404code.html"; 


class HttpRequest
{
public:
    HttpRequest()
    {
        _hash["html"] = "text/html";
        _hash["jpg"] = "image/jpeg";
        _hash["png"] = "image/png";
    }
    
    void deserialize(std::string &text)
    {
        while (_head.size() == 0 || _head.back().size() != 0)
        {
            size_t pos = text.find(sep);
            if (pos == std::string::npos)
                return;
            _head.emplace_back(text.substr(0, pos));
            text.erase(0, pos + sep.size());
        }

        _content = text;
    }

    void Debuf()
    {
        for (auto &i : _head)
        {
            std::cout << "==================================================" << std::endl;
            std::cout << i << std::endl;
        }
        std::cout << "==================================================" << std::endl;
        std::cout << _content << std::endl;
    }

    void Prase()
    {
        if (_head.size() == 0)
            return;

        std::stringstream ss(_head[0]);
        ss >> _method >> _url >> _version;

        if (_url == "/" || _url == "/index.html")
        {
            _path = path;
            _path += '/';
            _path += homepage;
        }
        else
        {
            _path = path;
            _path += _url;
        }

        size_t pos = _url.rfind('.');
        if(pos == std::string::npos)
            _suffix = "html";
        else{
            _suffix = _url.substr(pos);
        }
    }

    std::string SuffixMap()
    {
        if(_hash.count(_suffix))
            return _hash[_suffix];
        else    
            return _hash["html"];
    }

    std::string GetPath()
    {
        return _path;
    }

private:
    std::vector<std::string> _head;
    std::string _content;

    std::string _method;
    std::string _url;
    std::string _version;
    std::string _path;

    std::string _suffix;
    std::unordered_map<std::string, std::string> _hash;
};

class HttpResponse
{
public:
    static std::string ReadHtml(const char *htmlpath)
    {
        //图像是二进制文件需要二进制读取
        char buffer[4096];
        int fd = open(htmlpath, O_RDONLY);
        if (fd < 0)
            return "";
        std::string Html;
        while (1)
        {
            //memset(buffer, 0, sizeof(buffer));
            ssize_t n = read(fd, buffer, sizeof(buffer));
            if (n <= 0)
                break;
            //系统调用二进制读取和字符读取区别是不用预留 '\0'的位置

            // buffer[n] = '\0';
            // Html += buffer;

            //直接追加原字节
            Html.append(buffer, n);
        }

        //老是忘记关文件
        close(fd);
        return Html;
    }

    static std::string BildMsg(std::string content, std::string Type)
    {
        std::string msg;

        if(content.size() == 0)
            content = ReadHtml(code404.c_str());
       
        msg = "Http1.1 200 OK\r\n";
        msg += "Content-Type: ";
        msg +=  Type;
        msg += "\r\n";
        msg += "Content-Length: ";
        msg += std::to_string(content.size());
        msg += "\r\n\r\n";
        msg += content;

        // msg = "Http1.1 302 Found\r\n";
        // msg += "Location: https://gitee.com/whb-helloworld/\
        //      108/blob/master/lesson44/HttpServer.hpp\r\n\r\n";


      
        return msg;
    }
};

class HttpServer
{
public:
    HttpServer(uint16_t port = 8080) : _port(port) {};

    void Init()
    {
        _sock.Socket();
        _sock.Bind(_port);
        _sock.Listen();
    }

    void Start()
    {
        std::string ClientIp;
        uint16_t ClientPort;

        while (1)
        {
            int sockid = _sock.Accept(ClientIp, ClientPort);
            if (sockid < 0)
                continue;

            pthread_t pid;
            pthread_create(&pid, nullptr, ThreadRun, &sockid);
        }
    }

    static void Http(int sockid)
    {
        char buffer[4096];
        int n = recv(sockid, buffer, sizeof(buffer) - 1, 0);
        if (n < 0)
            return;

        buffer[n] = '\0';
        std::string text = buffer;

        HttpRequest req;
        req.deserialize(text);
        req.Debuf();
        req.Prase();

        std::string ret = HttpResponse::ReadHtml(req.GetPath().c_str());
        ret = HttpResponse::BildMsg(ret, req.SuffixMap());
        send(sockid, ret.c_str(), ret.size(), 0);
    }

    static void *ThreadRun(void *ptr)
    {
        pthread_detach(pthread_self());
        int *sockid = static_cast<int *>(ptr);
        Http(*sockid);
        return nullptr;
    }

private:
    Sock _sock;
    uint16_t _port;
};
